package com.zhangsun.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhangsun.expection.BusinessException;
import com.zhangsun.service.RedisService;
import com.zhangsun.system.component.SystemComponent;
import com.zhangsun.system.entity.ResourceEntity;
import com.zhangsun.system.entity.RoleEntity;
import com.zhangsun.system.entity.RoleResourceEntity;
import com.zhangsun.system.enums.ResourceTypeEnum;
import com.zhangsun.system.mapper.ResourceMapper;
import com.zhangsun.system.mapper.RoleResourceMapper;
import com.zhangsun.system.service.ResourceService;
import com.zhangsun.system.vo.resource.ResourceEditVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * <p>
 * 资源 服务实现类
 * </p>
 *
 * @author zhangsun
 * @since 2019-07-23
 */
@Service
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, ResourceEntity> implements ResourceService {

    @Autowired
    private RoleResourceMapper roleResourceMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private SystemComponent systemComponent;

    @Override
    public List<ResourceEntity> findResourcesByRoles(List<RoleEntity> roles, String userId) {
        String resourcesObject = (String) redisService.get(userId + ":resource");
        if (StrUtil.isNotBlank(resourcesObject)) {
            return JSON.parseArray(resourcesObject, ResourceEntity.class);
        }

        Set<String> roleIds = new HashSet<>();
        if (CollUtil.isNotEmpty(roles)) {
            roles.forEach(r -> roleIds.add(r.getId()));
            List<ResourceEntity> resources = baseMapper.findResourcesByRoles(roleIds);
            redisService.set(userId + ":resource", JSON.toJSONString(resources));
            return resources;
        }
        return null;
    }

    @Override
    public List<ResourceEntity> findResourceTree() {
        LambdaQueryWrapper<ResourceEntity> queryWrapper = new QueryWrapper<ResourceEntity>().lambda();
        queryWrapper.orderByAsc(ResourceEntity::getSort);
        List<ResourceEntity> resources = baseMapper.selectList(queryWrapper);
        return systemComponent.getResourceTree(resources, false);
    }

    @Override
    public List<ResourceEntity> findMenuTree() {
        LambdaQueryWrapper<ResourceEntity> queryWrapper = new QueryWrapper<ResourceEntity>().lambda();
        List<ResourceEntity> resources = baseMapper.selectList(queryWrapper);
        return systemComponent.getResourceTree(resources, true);
    }

    @Override
    public void create(ResourceEditVo vo) {
        LambdaQueryWrapper<ResourceEntity> queryWrapper = new QueryWrapper<ResourceEntity>().lambda();
        queryWrapper.eq(ResourceEntity::getPermission, vo.getPermission());
        int count = baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new BusinessException("该权限字符串已存在，不能重复");
        }

        if (ResourceTypeEnum.MENU.equals(vo.getType())) {
            LambdaQueryWrapper<ResourceEntity> queryWrapper1 = new QueryWrapper<ResourceEntity>().lambda();
            queryWrapper1.eq(ResourceEntity::getUrl, vo.getUrl());
            int count1 = baseMapper.selectCount(queryWrapper1);
            if (count1 > 0) {
                throw new BusinessException("该地址已存在，不能重复");
            }
        }

        ResourceEntity resourceEntity = new ResourceEntity();
        BeanUtil.copyProperties(vo, resourceEntity);
        resourceEntity.insert();
    }

    @Override
    public ResourceEntity findById(String id) {
        ResourceEntity resource = baseMapper.selectById(id);
        if (resource != null) {
            List<String> parentIds = new ArrayList<>();
            findParentId(resource.getParentId(), parentIds);
            resource.setParentIds(parentIds);
        }
        return resource;
    }

    private void findParentId(String parentId, List<String> parentIds) {
        if (StrUtil.isNotBlank(parentId)) {
            parentIds.add(0, parentId);
            ResourceEntity resource = baseMapper.selectById(parentId);
            if (resource != null) {
                findParentId(resource.getParentId(), parentIds);
            }
        }
    }

    @Override
    public void update(String id, ResourceEditVo vo) {
        LambdaQueryWrapper<ResourceEntity> queryWrapper = new QueryWrapper<ResourceEntity>().lambda();
        queryWrapper.eq(ResourceEntity::getPermission, vo.getPermission())
                .ne(ResourceEntity::getId, id);
        int count = baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new BusinessException("该权限字符串已存在，不能重复");
        }

        if (ResourceTypeEnum.MENU.equals(vo.getType())) {
            LambdaQueryWrapper<ResourceEntity> queryWrapper1 = new QueryWrapper<ResourceEntity>().lambda();
            queryWrapper1.eq(ResourceEntity::getUrl, vo.getUrl())
                    .ne(ResourceEntity::getId, id);
            int count1 = baseMapper.selectCount(queryWrapper1);
            if (count1 > 0) {
                throw new BusinessException("该地址已存在，不能重复");
            }
        }

        ResourceEntity resourceEntity = new ResourceEntity();
        BeanUtil.copyProperties(vo, resourceEntity);
        resourceEntity.setId(id);
        resourceEntity.updateById();
    }

    @Transactional
    @Override
    public void delete(String id) {
        List<String> resourceIds = new ArrayList<>();
        resourceIds.add(id);
        findChildrenId(id, resourceIds);
        baseMapper.deleteBatchIds(resourceIds);

        LambdaQueryWrapper<RoleResourceEntity> queryWrapper = new QueryWrapper<RoleResourceEntity>().lambda();
        queryWrapper.in(RoleResourceEntity::getResourceId, resourceIds);
        roleResourceMapper.delete(queryWrapper);
    }

    private void findChildrenId(String id, List<String> childrenIds) {
        LambdaQueryWrapper<ResourceEntity> queryWrapper = new QueryWrapper<ResourceEntity>().lambda();
        queryWrapper.eq(ResourceEntity::getParentId, id);
        List<ResourceEntity> resources = baseMapper.selectList(queryWrapper);
        if (CollUtil.isNotEmpty(resources)) {
            resources.forEach(item -> {
                childrenIds.add(item.getId());
                findChildrenId(item.getId(), childrenIds);
            });
        }
    }
}
